#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/signalfd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/signalfd.h>
#include <sys/types.h>
#include "sender.h"
#include "test_mgr.h" 
#include <sys/time.h>

#define SEND_INTERVAL 1
static int32_t ON_MSG = SIGRTMIN + 7;

static long get_ms_time() {
    struct timeval tv;
    memset(&tv, 0x00, sizeof(tv));

    gettimeofday(&tv, nullptr);
    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

int sender::send_signal(int dest_pid, int signo) {
    static pid_t pid = getpid();
    
    sigval value;
    memset(&value, 0x00, sizeof(sigval));
    value.sival_int = pid;

    int ret = sigqueue(dest_pid, signo, value);
    if (ret != 0)
        perror("sigqueue error");

    return ret;
}

static int stop_timer_handle(uv_timer_t* handle) {
    int ret = uv_timer_stop(handle);
    return ret;
}

static int stop_timer_handle(uv_idle_t* handle) {
    int ret = uv_idle_stop(handle);
    return ret;
}

template<typename T>
void sender::timer_cb(T* handle) {
    sender* mgr = static_cast<sender*>(handle->data);

    static int total = test_mgr::get()->msg_per_robot();
    mgr->timestamp_.push_back(get_ms_time());

    mgr->send_signal(mgr->pid_, SIGRTMIN + 7);
    test_mgr::get()->add_msg_send_count();

    if (++mgr->send_num_ < total) return;

    int ret = stop_timer_handle(handle);
    if(ret != 0) {
        sk_error("uv_timer_stop error:%s", uv_err_name(ret));
    }
}

int sender::test_start() {
    int ret = uv_timer_init(loop_, &timer_);
    if (ret != 0) {
        sk_error("uv_timer_init error:%s", uv_err_name(ret));
        return ret;
    }

    ret = uv_timer_start(&timer_, timer_cb, 0, SEND_INTERVAL);
    if (ret != 0) {
        sk_error("uv_timer_init error:%s", uv_err_name(ret));
        return ret;
    }

    return 0;
}

int sender::test_start(int flag) {
    int ret = uv_idle_init(loop_, &idle_);
    if (ret != 0) {
        sk_error("uv_idle_init error:%s", uv_err_name(ret));
        return ret;
    }

    ret = uv_idle_start(&idle_, timer_cb);
    if (ret != 0) {
        sk_error("uv_timer_init error:%s", uv_err_name(ret));
        return ret;
    }

    return 0;
}

int sender::test_stop() {
    int ret = this->sw_->stop();
    if (ret != 0) return ret;

    ret = uv_timer_stop(&timer_);
    if(ret != 0) {
        sk_error("uv_timer_stop error:%s", uv_err_name(ret));
        return ret;
    }

    return 0;
}

int sender::watch_signals() {
    sw_ = signal_watcher::create(loop_);

    if (!sw_) {
        sk_error("create signal watcher error");
        return -1;
    }

    sw_->set_signal_callback(std::bind(&sender::handle_signal, this, std::placeholders::_1));

//    int ret = sw_->watch(SIGINT);
//    if(ret != 0) return ret;
    
    int ret = sw_->watch(SIGPIPE);
    if(ret != 0) return ret;

    ret = sw_->watch(SIGTERM);
    if(ret != 0) return ret;

    ret = sw_->watch(SIGUSR1);
    if(ret != 0) return ret;

    ret = sw_->watch(ON_MSG);
    if(ret != 0) return ret;

    return sw_->start();
}

void sender::handle_signal(const struct signalfd_siginfo* info) {
    if (info == nullptr) return;

    int signo = static_cast<int>(info->ssi_signo);

    if (signo == ON_MSG && !timestamp_.empty()) {
        long time_interval = get_ms_time() - timestamp_.front();
        test_mgr::get()->add_msg_recv_cost(time_interval);
        timestamp_.pop_front();
        test_mgr::get()->add_msg_recv_count();
    }
    else
      sk_error("timestamp error\n");
}
